#include "TulingUploadImpl.h"
#include "TulingLog.h"
#include "TulingData.h"
#include "cJson.h"
#include <stdio.h>
#include <netdb.h>

static char pUploadHead[] = 
	"POST /resources/file/upload?apiKey=%s HTTP/1.1\r\n"
    "Host: %s\r\n"
	"Connection: keep-alive\r\n"
	"Content-Length: %d\r\n"
	"Content-Type: multipart/form-data; boundary=%s\r\n\r\n";


static char pBoundary[] =
	"----WebKitFormBoundaryfEgCQuURR7zTbs4F";

static char pUpLoadPath[]="/resources/file/upload?apiKey=%s";

static char pUploadParam1[] =
	"--%s\r\n";

static char pUploadParam2[] = 
	"Content-Disposition: form-data; name=\"speech\"; filename=\"test8k16b.amr\"\r\n"
	"Content-Type: application/octet-stream\r\n\r\n";

static char pUploadParam3[] = 
	"\r\n--%s--\r\n";


#define SEND_BUFF_SIZE 512
static char pSendBuff[SEND_BUFF_SIZE];
static UploadRsp urRsp;
extern TulingData	tadRingBuff;

TulingUpload::TulingUploadImpl::TulingUploadImpl()
	:thUpload(osPriorityNormal)
	,bIsInit(false)
{

}

TulingUpload::TulingUploadImpl::~TulingUploadImpl()
{

}

void TulingUpload::TulingUploadImpl::SetEventListener(IOnEvent* _pEvent)
{
	if(!bIsInit)return;
	pEvent = _pEvent;
}


void TulingUpload::TulingUploadImpl::Init()
{
	pProfile = (TulingProfile *)TulingConfig::Instance().GetProfile();
	thUpload.start(this,&TulingUploadImpl::RunUpload);
	bIsInit = true;
}

void TulingUpload::TulingUploadImpl::Start()
{	
	if(!bIsInit)return;	
	thUpload.signal_set(0x01);
}

void TulingUpload::TulingUploadImpl::Stop()
{
	if(!bIsInit)return;
}

void TulingUpload::TulingUploadImpl::on_start()
{
	tadRingBuff.Clear();		
	char *strAmrHead = "#!AMR\n";
	tadRingBuff.Write((unsigned char *)strAmrHead,strlen(strAmrHead));	
}

void TulingUpload::TulingUploadImpl::on_data(const void * pData,int nLen)
{
	int nFreeSize = tadRingBuff.GetFreeSize();
	TULING_LOGD("nFreeSize = %d",nFreeSize);	
	if(nFreeSize > nLen)
	{
		tadRingBuff.Write((unsigned char *)pData,nLen);
	}
}

void TulingUpload::TulingUploadImpl::on_stop()
{
	Start();
}


void TulingUpload::TulingUploadImpl::ParseUploadRsp(unsigned char* strUploadMsg,int nMsgLen)
{	
	bool bRet = false;
	if(nMsgLen == 0) return ;
	cJSON * pJson = cJSON_Parse((char *)strUploadMsg);
	if(!pJson)return ;	
	memset(&urRsp,0,sizeof(UploadRsp));
	cJSON *pSub = cJSON_GetObjectItem(pJson, "code");	
	if(pSub)urRsp.nCode= pSub->valueint;	
	pSub = cJSON_GetObjectItem(pJson, "desc");
	if(pSub)sprintf(urRsp.strDesc,"%s",pSub->valuestring);
	pSub = cJSON_GetObjectItem(pJson, "payload");
	if(pSub)sprintf(urRsp.strPayload,"%s",pSub->valuestring);
	cJSON_Delete(pJson);
}

void TulingUpload::TulingUploadImpl::RunUpload()
{	
	char pTemp[128]={0};
	int nPort = 80;
	int nRet = -1;
	int nSockFd = -1;
	struct hostent *server;
	struct sockaddr_in serv_addr; 
	char *pServerAddr = pProfile->RC_reportcfg.strReportServerAddr;
	//char *pApiKey = pProfile->MC_mqttcfg.strBakApiKey;
	char *pApiKey = pProfile->AC_wificfg.strApiKey;
	
	int nContentLength = 0;
	int nDataLength = 0;
	int nSendLen = 0;
	int nReadLen = 0;
	int nTotalReadLen = 0;
	
	while(1)
	{
		thUpload.signal_wait(0x01);
		TULING_LOGI("Entry RunUpload");
		TULING_LOGI("thread: id = %x", thUpload.gettid());	
		do
		{		
			nContentLength = 0;
			nDataLength = 0;
			nSendLen = 0;
			nReadLen = 0;
			nTotalReadLen = 0;
			memset(pTemp,0,sizeof(pTemp));		
			memset(pSendBuff,0,SEND_BUFF_SIZE);
			memset(&urRsp,0,sizeof(UploadRsp));
		
			nSockFd = socket(AF_INET, SOCK_STREAM, 0);
			if (nSockFd < 0) {printf("ERROR opening socket\n");break;}
			server = gethostbyname(pServerAddr);
			if (server == NULL) {printf("ERROR, no such host\n");break;}
			memset(&serv_addr,0,sizeof(serv_addr));
			serv_addr.sin_family = AF_INET;
			serv_addr.sin_port = htons(nPort);
			memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
			nRet = connect(nSockFd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
			if(nRet !=0 )break;	

			// build data
			memset(pSendBuff,0,SEND_BUFF_SIZE);				
			sprintf(pTemp,pUploadParam1,pBoundary);
			nContentLength +=strlen(pTemp);			
			memset(pTemp,0,sizeof(pTemp));
			nContentLength += strlen(pUploadParam2);			
			sprintf(pTemp,pUploadParam3,pBoundary);
			nContentLength +=strlen(pTemp);	
			nDataLength = tadRingBuff.GetDataSize();
			nContentLength += nDataLength;
			sprintf(pSendBuff,pUploadHead,pApiKey,pServerAddr,nContentLength,pBoundary);
			sprintf(pSendBuff + strlen(pSendBuff),pUploadParam1,pBoundary);
			strcat(pSendBuff,pUploadParam2);	

			// send data
			nSendLen = send(nSockFd,pSendBuff,strlen(pSendBuff),0);
			TULING_LOGD("%s",pSendBuff);			
			while(nTotalReadLen < nDataLength)
			{	
				nReadLen = (nDataLength-nTotalReadLen >= 1024)?1024:(nDataLength-nTotalReadLen);				
				nSendLen = send(nSockFd,tadRingBuff.GetReadPtr(),nReadLen,0);
				if(nSendLen <= 0 )break;
				tadRingBuff.ReadDone(nSendLen);
				nTotalReadLen +=nSendLen;				
			}			
			memset(pSendBuff,0,SEND_BUFF_SIZE);
			sprintf(pSendBuff,pUploadParam3,pBoundary);
			nSendLen = send(nSockFd,pSendBuff,strlen(pSendBuff),0);
			if(nSendLen <= 0 )break;
			
			memset(pSendBuff,0,SEND_BUFF_SIZE);
			nSendLen = recv(nSockFd,pSendBuff,SEND_BUFF_SIZE,0);
			if(nSendLen <= 0 )break;
			
			char *pBody = strstr(pSendBuff, "\r\n\r\n");
			if(pBody!=NULL)
			{
				ParseUploadRsp((unsigned char *)pBody,strlen(pBody));
				TULING_LOGI("%s",pSendBuff);
				if(pEvent)pEvent->on_upload(&urRsp);			
			}			
		}while(0);
		close(nSockFd);
		nSockFd = -1;
		tadRingBuff.Clear();		
		TULING_LOGI("Leave RunUpload");
	}
}


